package nachos.threads;

import nachos.machine.*;

/**
 * A <i>communicator</i> allows threads to synchronously exchange 32-bit
 * messages. Multiple threads can be waiting to <i>speak</i>,
 * and multiple threads can be waiting to <i>listen</i>. But there should never
 * be a time when both a speaker and a listener are waiting, because the two
 * threads can be paired off at this point.
 */
public class Communicator {
    /**
     * Allocate a new communicator.
     */
    public Communicator() {
    }

    /**
     * Wait for a thread to listen through this communicator, and then transfer
     * <i>word</i> to the listener.
     *
     * <p>
     * Does not return until this thread is paired up with a listening thread.
     * Exactly one listener should receive <i>word</i>.
     *
     * @param	word	the integer to transfer.
     */
    public void speak(int word) {
      lock.acquire();
      if(speakCount == 0 && listenCount > 0){
        message = word;
        listener.wake();
      }
      else{
        speakCount++;
        speaker.sleep();
        message = word;
        speakCount--;
        listener.wake();
      }
      lock.release();
    }

    /**
     * Wait for a thread to speak through this communicator, and then return
     * the <i>word</i> that thread passed to <tt>speak()</tt>.
     *
     * @return	the integer transferred.
     */    
    public int listen() {
      lock.acquire();
      listenCount++;
      if(speakCount == 0){
        listener.sleep();
      }
      else{
        speaker.wake();
        listener.sleep();
      }
        int tmpmessage = message;
        listenCount--;
        lock.release();
        return tmpmessage;
    }

    private int message;
    private Lock lock = new Lock();
    private Condition2 speaker = new Condition2(lock);
    private Condition2 listener = new Condition2(lock);
    private int speakCount = 0;
    private int listenCount = 0;
}
